import FairyEditor = CS.FairyEditor;
import fgui = CS.FairyGUI;
var App = FairyEditor.App;
/**填充样式 */
const FillType = [
    "none",
    "scale",
    "scaleNoBorder",
    "scaleMatchHeight",
    "scaleMatchWidth",
    "scaleFree",
];
/**水平对齐方式 */
const Align = [
    "left",
    "center",
    "right"
];
/**竖直对齐方式 */
const VAlign = [
    "top",
    "middle",
    "bottom"
]
export class GLoader3DSpineExtension extends FairyEditor.View.PluginInspector {
    static create() {
        App.inspectorView.AddInspector(() => new GLoader3DSpineExtension, "spine_ext", "【非会员】模型/特效");
        App.docFactory.ConnectInspector("spine_ext", "", false, false);
    }
    /**资源地址 */
    private url: fgui.GLabel;
    /**自动大小 */
    private autoSize: fgui.GButton;
    /**填充处理 */
    private fill: fgui.GComboBox;
    /**仅允许缩小 */
    private shrinkOnly: fgui.GButton;
    /**水平对齐方式 */
    private align: fgui.Controller;
    /**竖直对齐方式 */
    private verticalAlign: fgui.Controller;
    /**颜色 */
    private color: fgui.GButton;
    /**动画名称 */
    private animationName: fgui.GComboBox;
    /**播放 */
    private playing: fgui.GButton;
    /**循环 */
    private loop: fgui.GButton;
    /**帧 */
    private frame: fgui.GLabel;
    /**皮肤 */
    private skinName: fgui.GComboBox;
    /**发布时清空 */
    private clearOnPublish: fgui.GButton;
    /**当前组件名称 */
    private name: string;

    constructor() {
        super();
        FairyEditor.FObject.loadingSnapshot = false;
        const panel = this.panel = fgui.UIPackage.CreateObject("Builder", "Loader3DPropsPanel").asCom;
        
        //资源地址
        this.url = panel.GetChild('url').asLabel;
        //自动大小
        this.autoSize = panel.GetChild('autoSize').asButton;
        this.fill = panel.GetChild('fill').asComboBox;
        this.shrinkOnly = panel.GetChild('shrinkOnly').asButton;
        this.align = panel.GetController('align');
        this.verticalAlign = panel.GetController('verticalAlign');
        this.color = panel.GetChild('color').asButton;
        //动画名称
        this.animationName = panel.GetChild('animationName').asComboBox;
        this.playing = panel.GetChild('playing').asButton;
        this.loop = panel.GetChild('loop').asButton;
        this.frame = panel.GetChild('frame').asLabel;
        this.skinName = panel.GetChild('skinName').asComboBox;
        this.clearOnPublish = panel.GetChild('clearOnPublish').asButton;
        this.updateAction = () => { return this.update(); };
    }
    /**组件改名 */
    private changeName(): void {
        const parent = this.panel.parent;
        const basic = parent.GetChild('basic').asCom;
        this.name = basic.GetChild('name').asComboBox.text;
        // console.log('更新组件命名:', this.name);
    }
    private async onResourceInput(): Promise<void> {
        await this.wait(100);
        const comp = this.content;
        const url = this.url.title;
        if (url == comp.url) {
            return;
        }
        const asset = <FairyEditor.SkeletonAsset>App.project.GetItemByURL(url)?.GetAsset();
        if (!!url && !(asset instanceof FairyEditor.SkeletonAsset)) {
            App.Alert('输入骨骼动画资源！！！');
            this.init();
            return;
        }
        comp.url = this.url.title;
        //写入xml，保存文档
        this.syncXML('url', this.url.title);
        this.save();
        await this.wait(100);
        this.init();
        this.onAnimationChange();
        this.onSkinChange();
    }
    private update(): boolean {
        const parent = this.parent.asList;
        if (!parent || !(parent instanceof fgui.GList) || !parent.GetChild('loader3D')) {
            const i = parent.GetChildIndex(this.panel) - 1;
            if (i > -1) {
                const title = parent.GetChildAt(i);
                title.visible = false;
            }
            this.panel.visible = false;
            parent.foldInvisibleItems = true;
            this.clearListener();
        }
        else {
            // console.log('刷新Inspector');
            this.panel.visible = true;
            const i = parent.GetChildIndex(this.panel) - 1;
            if (i > -1) {
                const title = parent.GetChildAt(i);
                title.visible = true;
            }
            const basic = parent.GetChild('basic').asCom;
            const nameText = basic.GetChild('name').asComboBox;
            this.name = nameText.text;
            this.init();
            this.addListener();
        }
        return true;
    }
    private map(comp) {
        let log = '';
        for (let i = 0; i < comp.numChildren; i++) {
            const child = comp.GetChildAt(i);
            // log += `${child.name}\n`
            console.log(child.name);
        }
    }

    /**同步写入xml文件 */
    private syncXML(key: string, value: string): void {
        // console.log('写入XML:', key, value, this.name);
        const packageItem = App.activeDoc.packageItem;
        const content = CS.System.IO.File.ReadAllText(packageItem.file);
        const contentList = content.split('\n');
        for (let i = 0, cnt = contentList.length; i < cnt; i++) {
            let line = contentList[i];
            if (line.indexOf('loader3D') < 0 || !line.match(new RegExp(`name="${this.name}"`))) {
                continue;
            }
            if (line.indexOf(`${key}=`) < 0) {
                line = line.replace('/>', ` ${key}="${value}" />`);
            }
            else {
                const reg = new RegExp(`${key}="([^"]+)"`);
                line = line.replace(reg, `${key}="${value}"`);
            }
            contentList[i] = line;
            break;
        }
        const content1 = contentList.join('\n');
        CS.System.IO.File.WriteAllText(packageItem.file, content1);
        App.activeDoc.Save();
    }
    /**删除属性键 */
    private deleteKey(key: string): void {
        // console.log('删除键', key);
        const packageItem = App.activeDoc.packageItem;
        const content = CS.System.IO.File.ReadAllText(packageItem.file);
        const contentList = content.split('\n');
        for (let i = 0, cnt = contentList.length; i < cnt; i++) {
            let line = contentList[i];
            if (line.indexOf('loader3D') < 0 || !line.match(new RegExp(`name="${this.name}"`))) {
                continue;
            }
            const reg = new RegExp(`${key}="(ui://){0,1}\\w*"`)
            line = line.replace(reg, "");
            contentList[i] = line;
            break;
        }
        const content1 = contentList.join('\n');
        CS.System.IO.File.WriteAllText(packageItem.file, content1);
        App.activeDoc.Save();
    }

    private async wait(ss: number): Promise<void> {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve();
            }, ss);    
        })
    }

    /**添加组件监听 */
    private async addListener(): Promise<void> {
        // await this.wait(100);
        //组件改名
        const parent = this.parent;
        //基础属性面板
        const basic = parent.GetChild('basic')?.asCom;
        if (!basic) {
            return;
        }
        const name = basic.GetChild('name').asComboBox;
        name.onChanged.Add(this.changeName.bind(this));
        //切换spine
        this.url.onTouchEnd.Add(this.onResourceInput.bind(this));
        const nameText = this.url.GetChild('nameText');
        nameText.onPositionChanged.Add(this.onResourceInput.bind(this));
        //动画名切换
        this.animationName.onChanged.Add(this.onAnimationChange.bind(this));
        //皮肤名切换
        this.skinName.onChanged.Add(this.onSkinChange.bind(this));
        //填充处理
        this.fill.onChanged.Add(this.onFillChange.bind(this))
        //播放
        this.playing.onClick.Add(this.onPlayingChange.bind(this));
        //循环
        this.loop.onClick.Add(this.onLoopChange.bind(this));
        //自动大小
        this.autoSize.onClick.Add(this.onAutoSizeChange.bind(this));
        //仅允许缩小
        this.shrinkOnly.onClick.Add(this.onShrinkOnlyChange.bind(this));
        //发布时清空
        this.clearOnPublish.onClick.Add(this.onClearOnPublishChange.bind(this));
        //水平对齐方式
        this.align.onChanged.Add(this.onAlignChange.bind(this));
        //垂直对齐方式
        this.verticalAlign.onChanged.Add(this.onVAlignChange.bind(this));
        //颜色
        const graph = this.color.GetChild('n1').asGraph;
        graph.onFocusOut.Add(this.onColorChange.bind(this, graph));
    }

    private async clearListener(): Promise<void> {
        // await this.wait(100);
        //组件改名
        const parent = this.parent;
        //基础属性面板
        const basic = parent.GetChild('basic')?.asCom;
        if (!basic) {
            return;
        }
        const name = basic.GetChild('name').asComboBox;
        name.onChanged.Clear();
        //切换spine
        this.url.onTouchEnd.Clear();
        const nameText = this.url.GetChild('nameText');
        nameText.onPositionChanged.Clear();
        //动画名切换
        this.animationName.onChanged.Clear();
        //皮肤名切换
        this.skinName.onChanged.Clear();
        //填充处理
        this.fill.onChanged.Clear();
        //播放
        this.playing.onClick.Clear();
        //循环
        this.loop.onClick.Clear();
        //自动大小
        this.autoSize.onClick.Clear();
        //仅允许缩小
        this.shrinkOnly.onClick.Clear();
        //发布时清空
        this.clearOnPublish.onClick.Clear();
        //水平对齐方式
        this.align.onChanged.Clear();
        //垂直对齐方式
        this.verticalAlign.onChanged.Clear();
        //颜色
        const graph = this.color.GetChild('n1').asGraph;
        graph.onFocusOut.Clear();
    }

    /**初始化 */
    private async init(): Promise<void> {
        const comp = <FairyEditor.FLoader3D>App.activeDoc.content.GetChild(this.name);
        const asset = <FairyEditor.SkeletonAsset>comp.contentRes.packageItem?.GetAsset();
        if (!asset) {
            // console.log('initialize none asset gloader3d compoent');
        }
        let i: number = 3;
        const title = this.parent.GetChildAt(0).asCom;
        if (title) {
            const text = title.GetChild('title')?.text;
            text && text == '包围' && (i = 5);
        }
        const panelO = this.parent.GetChildAt(i).asCom;
        const url = panelO.GetChild('url').asLabel;
        this.url.GetController('c1').selectedIndex = url.GetController('c1').selectedIndex;
        this.url.GetController('grayed').selectedIndex = url.GetController('grayed').selectedIndex;
        await this.wait(100);
        this.url.title = url.title;
        const nameText = this.url.GetChild('nameText').asTextField;
        const nameText1 = url.GetChild('nameText').asTextField;
        await this.wait(100);
        this.url.icon = url.icon;
        if (nameText1.text.match(/(@\w+)$/)) {
            nameText.x = 20;
        } else {
            nameText.x = 1;
        }
        nameText.text = nameText1.text;
        nameText.color = nameText1.color;
        //动画名
        const animationName = panelO.GetChild('animationName').asComboBox;
        this.animationName.items = animationName.items;
        this.animationName.selectedIndex = animationName.selectedIndex;
        //皮肤
        const skin = panelO.GetChild('skinName').asComboBox;
        this.skinName.items = skin.items;
        this.skinName.selectedIndex = skin.selectedIndex;
        //填充方式
        const fill = panelO.GetChild('fill').asComboBox;
        this.fill.items = fill.items;
        this.fill.selectedIndex = fill.selectedIndex;
        //播放/循环
        this.playing.selected = panelO.GetChild('playing').asButton.selected;
        this.loop.selected = panelO.GetChild('loop').asButton.selected;
        //颜色
        const graph = this.color.GetChild('n1').asGraph;
        graph.color = panelO.GetChild('color').asButton.GetChild('n1').asGraph.color;
        //帧
        this.frame.title = panelO.GetChild('frame').asLabel.title;
        //对齐方式
        this.align.selectedIndex = panelO.GetController('align').selectedIndex;
        this.verticalAlign.selectedIndex = panelO.GetController('verticalAlign').selectedIndex;
        //自动大小
        this.autoSize.selected = panelO.GetChild('autoSize').asButton.selected;
        //发布时清除
        this.clearOnPublish.selected = panelO.GetChild('clearOnPublish').asButton.selected;
        //仅允许缩小
        this.shrinkOnly.selected = panelO.GetChild('shrinkOnly').asButton.selected;
    }

    private get parent(): fgui.GComponent {
        return this.panel.parent;
    }

    private get content(): FairyEditor.FLoader3D {
        return <FairyEditor.FLoader3D>App.activeDoc.content.GetChild(this.name);
    }

    private onAnimationChange(): void {
        let anim = this.content.animationName = this.animationName.title;
        if (this.animationName.selectedIndex == 0) {
            anim = '';
        }
        this.syncXML('animation', anim);
        this.save();
    }
    private onSkinChange(): void {
        const skin = this.content.skinName = this.skinName.title;
        this.syncXML('skin', skin);
        this.save();
    }
    private onFillChange(): void {
        const fillType = FillType[this.fill.selectedIndex];
        this.content.fill = fillType;
        if (fillType == 'none') {
            this.deleteKey('fill');
        } else {
            this.syncXML('fill', fillType);
        }
        this.save();
    }
    private onPlayingChange(): void {
        const playing = this.content.playing = this.playing.selected;
        this.save();
    }
    private onLoopChange(): void {
        const loop = this.content.loop = this.loop.selected;
        this.syncXML('loop', `${loop}`);
        this.save();
    }
    private onAutoSizeChange(): void {
        const autosize = this.content.autoSize = this.autoSize.selected;
        this.syncXML('autoSize', `${autosize}`);
        this.save();
    }
    private onShrinkOnlyChange(): void {
        const shrinkOnly = this.content.shrinkOnly = this.shrinkOnly.selected;
        this.syncXML('shrinkOnly', `${shrinkOnly}`);
        this.save();
    }
    private onClearOnPublishChange(): void {
        const clearOnPublish = this.content.clearOnPublish = this.clearOnPublish.selected;
        this.syncXML('clearOnPublish', `${clearOnPublish}`);
        this.save();
    }
    private onAlignChange(): void {
        const selectIndex = this.align.selectedIndex;
        const type = Align[selectIndex];
        this.content.align = type;
        if (type == 'left') {
            this.deleteKey('align');
        } else {
            this.syncXML('align', type);
        }
        this.save();
    }
    private onVAlignChange(): void {
        const selectIndex = this.verticalAlign.selectedIndex;
        const type = VAlign[selectIndex];
        this.content.verticalAlign = type;
        if (type == 'top') {
            this.deleteKey('vAlign');
        } else {
            this.syncXML('vAlign', type);
        }
        this.save();
    }
    private async onColorChange(graph: fgui.GGraph): Promise<void> {
        await this.wait(100);
        const color = graph.color;
        this.content.color = color;
        const hex = FairyEditor.ColorUtil.ToHexString(color);
        if (hex == '#ffffff') {
            this.deleteKey('color');
        } else {
            this.syncXML('color', hex);
        }
        this.save();
    }
    private save(): void {
        App.activeDoc.RefreshInspectors();
        App.activeDoc.Save();
    }
}
/**
 * @description 仅以此纪念-闫明晖同学-对该项目做出的贡献
 */
// function rgbToHex(rgb) {
//     let arr = rgb
//       .replace("rgb", "")
//       .replace("(", "")
//       .replace(")", "")
//       .split(",");
//     // 转十六进制
//     let h = parseInt(arr[0]).toString(16);
//     let e = parseInt(arr[1]).toString(16);
//     let x = parseInt(arr[2]).toString(16);
//     return "#" + h + e + x;
//   }
//   let rgb = "rgb(33,44,55)";
//   console.log(rgbToHex(rgb));